import { BadRequestException, Injectable } from '@nestjs/common';
import { PointsEntity } from './points.entity';
import { MoreThan, Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { isNil } from 'lodash';
import { PointsRulesEntity } from './points-rules/points-rules.entity';
import { MissionEntity } from '../mission/mission.entity';
import { PointsRulesService } from './points-rules/points-rules.service';
import { PointsLogService } from './points-log/points-log.service';
import { CommonStatus } from '~/common/entity/common.entity';
import { PointsEntityWithRank } from './points.model';
import { PointsGoodsService } from './points-goods/points-goods.service';
import { FindPointsRankDto } from './points.dto';
import { Pagination } from '~/helper/paginate/pagination';
import { paginate } from '~/helper/paginate';
import dayjs from 'dayjs';

@Injectable()
export class PointsService {
  constructor(
    @InjectRepository(PointsEntity)
    private readonly pointsRepository: Repository<PointsEntity>,
    private readonly pointsRulesService: PointsRulesService,
    private readonly pointsLogService: PointsLogService,
    private readonly pointsGoodsService: PointsGoodsService
  ) {}

  async countPointsRank(tenantId: number, userPoints: number): Promise<number> {
    const higherCount = await this.pointsRepository.count({
      where: {
        tenant: { id: tenantId },
        value: MoreThan(userPoints),
      },
      order: { createdAt: 'ASC' }, // 创建时间越早的排在最前
    });

    return higherCount + 1;
  }

  async countTenantPointRank({
    page,
    pageSize,
    tenantId,
  }: FindPointsRankDto & { tenantId: number }): Promise<Pagination<PointsEntity>> {
    const queryBuilder = await this.pointsRepository
      .createQueryBuilder('ah_points')
      .leftJoinAndSelect('ah_points.user', 'user')
      .leftJoinAndSelect('user.wechat', 'wechat') // 加载微信信息
      .where({
        tenant: { id: tenantId },
      })
      // 根据 创建时间排序（创建时间越早越在前）和 积分多少排序（越多越在前）
      // .orderBy('ah_points.createdAt', 'ASC')
      .addOrderBy('ah_points.value', 'DESC');

    const result: any = await paginate<PointsEntity>(queryBuilder, {
      page,
      pageSize,
    });

    // 对手机号进行脱敏处理
    if (result.items && result.items.length > 0) {
      result.items = result.items.map((item: Record<string, any>) => {
        if (item?.user?.wechat?.phone) {
          // 手机号脱敏：保留前3位和后4位，中间用****替代
          const mobile = item?.user?.wechat?.phone;
          if (mobile && mobile.length >= 7) {
            const maskedMobile =
              mobile.substring(0, 3) + '****' + mobile.substring(mobile.length - 4);
            item.user.wechat.phone = maskedMobile;
          }
        }
        return item;
      });
    }

    return result;
  }

  async getUserAndRank(userId: number, tenantId: number): Promise<Partial<PointsEntityWithRank>> {
    const points: PointsEntity = await this.getPointsByUserId(userId);

    const rank: number = await this.countPointsRank(tenantId, points.value);

    return { ...points, rank };
  }

  /**
   * 根据用户ID创建积分记录
   */
  async getPointsByUserId(userId: number): Promise<PointsEntity> {
    // 检查用户ID是否存在
    let points = await this.pointsRepository.findOne({ where: { user: { id: userId } } });

    if (isNil(points)) {
      points = await this.pointsRepository.save({
        user: { id: userId },
      });
    }

    return points;
  }

  /**
   * 根据用户ID查询积分记录
   */
  async findByUserId(userId: number, tenantId: number): Promise<Partial<PointsEntityWithRank>> {
    if (isNil(userId)) {
      return {
        value: 0,
        rank: 0,
      };
    }

    return await this.getUserAndRank(userId, tenantId);
  }

  async addPointsByMission(
    rule: PointsRulesEntity,
    mission: MissionEntity,
    userId: number,
    curCount: number
  ) {
    const points: number = await this.pointsRulesService.calcPointsByRule(rule, curCount);

    if (points > 0) {
      // 发放积分
      const userPoints = await this.pointsRepository.findOneBy({ user: { id: userId } });

      if (isNil(userPoints)) {
        // 创建积分记录
        const account = await this.getPointsByUserId(userId);

        await this.pointsRepository.update(account.id, {
          value: account.value + points,
          updatedAt: new Date(),
        });
      } else {
        await this.pointsRepository.update(userPoints.id, {
          value: userPoints.value + points,
          updatedAt: new Date(),
        });
      }

      // 积分记录
      await this.pointsLogService.create(
        {
          points,
          pointsType: CommonStatus.YES,
          hasReward: CommonStatus.YES,
          title: mission.name,
          missionId: mission.id,
          missionType: mission.missionType,
          missionRelatedData: mission.missionRelatedData,
        },
        userId
      );
    }
  }

  async exchangePointsGoodsCheck(
    userId: number,
    tenantId: number,
    goodsId: number
  ): Promise<{ canExchange: boolean; message: string }> {
    const points = await this.getPointsByUserId(userId);

    return await this.pointsGoodsService.canExchangeGoods(goodsId, points.value);
  }

  async exchangePointsGoods(userId: number, tenantId: number, goodsId: number): Promise<void> {
    // 兑换商品
    const goods = await this.pointsGoodsService.getGoods(goodsId);

    const userPoints = await this.pointsRepository.findOneBy({ user: { id: userId } });

    if (userPoints.value < goods.price) {
      throw new BadRequestException('积分不足，无法兑换');
    }

    await this.pointsGoodsService.exchangeGoods(userId, goods);

    await this.pointsRepository.update(userPoints.id, {
      value: userPoints.value - goods.price,
      updatedAt: new Date(),
    });

    await this.pointsLogService.create(
      {
        points: goods.price,
        pointsType: CommonStatus.NO,
        hasReward: CommonStatus.YES,
        title: `兑换商品${goods.name}`,
      },
      userId
    );
  }

  async getPointsHistory(userId: number) {
    // 获取过去七天的日期
    const today = new Date();
    const sevenDaysAgo = new Date();
    sevenDaysAgo.setDate(today.getDate() - 6); // 获取7天前的日期（包括今天，所以是-6）

    // 设置起始日期为当天的0点0分0秒
    sevenDaysAgo.setHours(0, 0, 0, 0);

    // 创建一个包含过去七天的日期数组
    const dates = [];
    const currentDate = new Date(sevenDaysAgo);

    // 生成过去7天的日期（包括今天）
    while (currentDate <= today) {
      dates.push(new Date(currentDate));
      currentDate.setDate(currentDate.getDate() + 1);
    }

    // 从积分日志服务获取过去七天内该用户的所有积分记录
    // 直接使用 Repository 进行查询以支持添加日期过滤条件
    const pointsLogs = await this.pointsLogService['pointsLogRepository'].find({
      where: {
        user: { id: userId },
        createdAt: MoreThan(sevenDaysAgo),
        pointsType: CommonStatus.YES, // 只获取积分增加的记录
      },
      order: {
        createdAt: 'ASC',
      },
    });

    // 按日期分组，统计每天的积分总和
    const dailyPoints = dates.map((date) => {
      const dateString = dayjs(date).format('YYYY-MM-DD');
      const startOfDay = new Date(date);
      const endOfDay = new Date(date);
      endOfDay.setHours(23, 59, 59, 999);

      // 过滤出当天的积分记录
      const dayLogs = pointsLogs.filter((log) => {
        const logDate = new Date(log.createdAt);
        return logDate >= startOfDay && logDate <= endOfDay;
      });

      // 计算当天的积分总和
      const totalPoints = dayLogs.reduce((sum, log) => sum + log.points, 0);

      return {
        date: dateString,
        points: totalPoints,
      };
    });

    return {
      history: dailyPoints,
    };
  }
}
